﻿using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

#region 目前有的功能
/// <summary>
/// (给Button,Toggle等组件扩展添加时间方法)
/// 通过子物体名字递归查找指定组件
/// 递归查找子物体
/// 查找所有场景中是否有某个组件
/// 将一个Texture2D转换成Sprite
/// 返回一个Texture2D完整的Rect
/// 判断是否点击在了UI上
/// 移动物体Sibling
/// </summary>
#endregion
public static class Utils
{
    #region 枚举
    public enum SiblingOpt
    {
        MoveOffect,
        Top, 
        Bottom
    }
    #endregion

    /// <summary>
    /// 通过子物体名字递归查找指定组件
    /// </summary>
    /// <typeparam name="T">要查找的组件</typeparam>
    /// <param name="childName">子物体的名字</param>
    /// <returns></returns>
    public static T GetComponentFromChild<T>(this Transform self, string childName) where T : Component
    {
        Transform child = self.Find(childName);
        if (child != null && child.TryGetComponent(out T childComponent))
        {
            if (childComponent != null) return childComponent;
        }
        foreach (Transform trans in self)
        {
            childComponent = trans.GetComponentFromChild<T>(childName);
            if (childComponent != null) return childComponent;
        }
        return null;
    }

    /// <summary>
    /// 递归查找子物体
    /// </summary>
    /// <param name="childName">子物体的名字</param>
    /// <returns></returns>
    public static Transform GetTransFromChild(this Transform self, string childName)
    {
        Transform child = self.Find(childName);
        if (child != null) return child;
        foreach (Transform trans in self)
        {
            child = trans.GetTransFromChild(childName);
            if (child != null) return child;
        }
        return null;
    }

    /// <summary>
    /// 查找所有场景中是否有某个组件
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="transName"></param>
    /// <returns></returns>
    /// <exception cref="NullReferenceException"></exception>
    public static T GetComponentFromAllScene<T>(string transName) where T : Component
    {
        GameObject tmp = GameObject.Find(transName);
        if (!tmp) throw new NullReferenceException("没有找该物体");
        if (tmp.TryGetComponent(out T com)) return com;
        else
        {
            DebugTools.Print($"没有找到 {transName} 物体上的 {typeof(T).Name} 组件 ");
            return null;
        }
    }

    /// <summary>
    /// 将一个Texture2D转换成Sprite
    /// </summary>
    /// <param name="texture2D">Texture</param>
    /// <param name="rect">正常为Texture</param>
    /// <param name="pivot"></param>
    /// <returns></returns>
    public static Sprite Texture2DToSprite(Texture2D texture2D, Rect rect, Vector2 pivot)
    {
        return Sprite.Create(texture2D, rect, pivot);
    }

    /// <summary>
    /// 返回一个Texture2D完整的Rect
    /// </summary>
    /// <param name="texture2D"></param>
    /// <returns></returns>
    public static Rect GetTexture2DRect(Texture2D texture2D)
    {
        return new Rect(0, 0, texture2D.width, texture2D.height);
    }


    private static GraphicRaycaster raycaster;
    /// <summary>
    /// 判断是否点击在了UI上
    /// </summary>
    /// <returns>点在了UI上</returns>
    public static bool IsClickUIPointer()
    {
        return EventSystem.current && EventSystem.current.IsPointerOverGameObject();
    }

    #region Button
    /// <summary>
    /// 查找一个Button（省事）
    /// </summary>
    /// <param name="childName">子物体的名字</param>
    /// <returns></returns>
    public static Button FindChildButton(this Transform self, string childName)
    {
        return GetComponentFromChild<Button>(self, childName);
    }
    /// <summary>
    /// 给一个Button添加一个事件
    /// </summary>
    /// <param name="action">事件</param>
    public static void OnRegister(this Button button, UnityAction action)
    {
        button.onClick.AddListener(action);
    }
    /// <summary>
    /// 给一个Button移除一个事件
    /// </summary>
    /// <param name="action">事件</param>
    public static void OnUnRegister(this Button button, UnityAction action)
    {
        button.onClick.RemoveListener(action);
    }
    /// <summary>
    /// 移除一个Button所有事件
    /// </summary>
    /// <param name="action">事件</param>
    public static void OnClear(this Button button)
    {
        button.onClick.RemoveAllListeners();
    }
    /// <summary>
    /// 模拟触发一个Button
    /// </summary>
    /// <param name="button"></param>
    public static void OnTriggerRegister(this Button button)
    {
        button.onClick?.Invoke();
    }
    #endregion
    #region Toggle
    /// <summary>
    /// 查找一个Toggle（省事）
    /// </summary>
    /// <param name="childName">子物体的名字</param>
    /// <returns></returns>
    public static Toggle FindChildToggle(this Transform self, string childName)
    {
        return GetComponentFromChild<Toggle>(self, childName);
    }
    /// <summary>
    /// 给一个Toggle添加一个事件
    /// </summary>
    /// <param name="action">事件</param>
    public static void OnRegister(this Toggle toggle, UnityAction<bool> action)
    {
        toggle.onValueChanged.AddListener(action);
    }
    /// <summary>
    /// 给一个Toggle移除一个事件
    /// </summary>
    /// <param name="action">事件</param>
    public static void OnUnRegister(this Toggle toggle, UnityAction<bool> action)
    {
        toggle.onValueChanged.RemoveListener(action);
    }
    /// <summary>
    /// 移除一个Toggle所有事件
    /// </summary>
    /// <param name="action">事件</param>
    public static void OnClaer(this Toggle toggle)
    {
        toggle.onValueChanged.RemoveAllListeners();
    }
    /// <summary>
    /// 模拟触发一个Toggle
    /// </summary>
    /// <param name="button"></param>
    public static void OnTriggerRegister(this Toggle toggle, bool isOn)
    {
        toggle.onValueChanged?.Invoke(isOn);
    }
    #endregion

    /// <summary>
    /// 移动物体在Hierarchy上的Sibling（层级）
    /// </summary>
    /// <param name="siblingOpt">如何移动</param>
    /// <param name="moveNum">移动多少(默认为1)，T，B无效</param>
    public static void ChangeTransSibling(this Transform trans, SiblingOpt siblingOpt,int offect)
    {
        switch (siblingOpt)
        {
            case SiblingOpt.MoveOffect:
                //这里防止了到-1导致到顶层的问题，若需要循环可自行注释掉
                if (offect < 0)
                {
                    if(trans.GetSiblingIndex()!=0)
                        trans.SetSiblingIndex(trans.GetSiblingIndex() + offect);
                }
                else
                    trans.SetSiblingIndex(trans.GetSiblingIndex() + offect);
                break;
            case SiblingOpt.Top:
                trans.SetAsLastSibling();
                break;
            case SiblingOpt.Bottom:
                trans.SetAsFirstSibling();
                break;
        }
    }
}
